/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - engine
// Copyright( c) 2013.  All Rights Reserved
//
// File:		AEngine.h
// Author:		Gianluca Belardelli
// Date:		05/04/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AENGINE_H_
#define _AENGINE_H_

#include <AECore.h>

#define AETRUE		1
#define AEFALSE		0
#define AENULL		0L

#if defined AE_OPENGL

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/wglew.h>

#include <gl\gl.h>  // Header File For The OpenGL32 Library
//#include <gl\glu.h> // Header File For The GLu32 Library

#elif defined AE_OPENGLES
#if defined AE_PLATFORM_ANDROID
	#include <EGL/egl.h>
	#include <GLES/gl.h>
#else

#endif
#elif defined AE_OPENGLES2
	#if defined AE_PLATFORM_ANDROID
		#include <GLES2/gl2.h>
		#include <GLES2/gl2ext.h>
	#else

	#endif

#elif defined AE_OPENGLES3
#if defined AE_PLATFORM_ANDROID
	#include <GLES3/gl3.h>
#else

#endif

#endif


// Definizione anticipata classi

class AEITaskManager;
class AEThreadPool;
class AESysParallelForTask;
class AESysTask;
class AEEngineSystem;
class AESystemTaskI;
class AESystemSceneI;
class AESystemObjectI;
class AEObserverI;
class AESubjectI;
class AEChangeManagerI;

#include <AEEngineTypes.h>
#include <geometry/containment/AEContainmentIncludes.h>

#include <memory/AERefCounter.h>
#include <memory/AEDefaultMemoryConfig.h>

#include <system/io/AEFileManager.h>
#include <system/io/AESearchPath.h>

#include <system/property/AEPropertyBase.h>
#include <system/property/AEProperty.h>
#include <system/property/AEPropertyContainer.h>

#include <system/interfaces/AEObserverI.h>
#include <system/interfaces/AESubjectI.h>
#include <system/interfaces/AEChangeManagerI.h>
#include <system/interfaces/AESystemSceneI.h>
#include <system/interfaces/AESystemObjectI.h>
#include <system/interfaces/AESystemAccessI.h>
#include <system/ccm/AESubject.h>
#include <system/ccm/AEChangeControlMgr.h>

#include <system/stats/AEEngineStats.h>
#include <system/AEEngineSystem.h>
#include <system/task/AESystemTaskI.h>
#include <system/thread/AEThreadWorkItem.h>
#include <system/task/AEITaskManager.h>
#include <system/task/AESysParallelForTask.h>
#include <system/task/AESysTask.h>
#include <system/task/AETaskManager.h>
#include <system/task/AEScheduler.h>
#include <system/thread/AEThreadPool.h>
#include <system/context/IAEContext.h>
#include <system/AEEngineSystem.h>
#include <system/AEUserDataObj.h>

#include <graphics/AEGraphicSystem.h>


#include <utils/AEStringUtils.h>

#include <application/IAEWindow.h>
#include <application/AEApplication.h>
#include <application/AEWindowManager.h>

#include <resource/AEResource.h>
#include <resource/AEResourceManager.h>
#include <resource/AEResourceLoaderI.h>
#include <graphics/buffers/AEGpuResource.h>
#include <graphics/buffers/AEVertexBuffer.h>
#include <graphics/buffers/AEIndexBuffer.h>

#include <graphics/AEVideoConfig.h>
#include <graphics/shaders/AEShadersInclude.h>
#include <graphics/renderer/renderstates/AEStateGroupRasterizer.h>
#include <graphics/renderer/renderstates/AERenderStates.h>

#include <graphics/AEPlatformInclude.h>
#include <graphics/texture/AETextureFileHeaders.h>

#include <graphics/texture/AETextureLoaderI.h>
#include <graphics/texture/AETexture.h>
#include <graphics/texture/AERenderableTexture.h>
#include <graphics/texture/AETextureFormatProviderI.h>
#include <graphics/texture/AETextureManager.h>


#include <graphics/texture/AEDefaultTextureFormatProvider.h>
#include <graphics/scene/AE3DObject.h>
#include <graphics/scene/AECamera.h>
#include <graphics/scene/collections/AERenderCollection.h>


#include <graphics/buffers/AEVertexBufferManager.h>
#include <graphics/AEColor.h>

#include <graphics/shaders/AEShaderProgramResource.h>
#include <graphics/shaders/AEShaderConstantTableEntry.h>
#include <graphics/shaders/AEShaderConstantTable.h>
#include <graphics/shaders/AEShaderConstantBuffer.h>
#include <graphics/shaders/AECompiledShaderPass.h>

#include <graphics/materials/AEMaterialTextures.h>
#include <graphics/materials/AEMaterial.h>

#include <geometry/AEVertexDescriptor.h>


#include <visibility/AEVisibilityData.h>
#include <geometry/mesh/AEMeshBuffer.h>
#include <geometry/mesh/AEBaseMesh.h>
#include <geometry/mesh/AEMeshManager.h>
#include <geometry/mesh/AEBaseSubmesh.h>
#include <geometry/mesh/AEStaticSubmesh.h>
#include <geometry/mesh/AEStaticMesh.h>

#include <graphics/scene/AEStaticGeometryInstance.h>
#include <geometry/mesh/AEStaticSubmeshInstance.h>
#include <geometry/mesh/AEStaticMeshInstance.h>



#include <graphics/IAEVideoDevice.h>
#include <graphics/IAERenderer.h>

#include <graphics/AERenderLoopI.h>
#include <graphics/context/AEContextViewProperties.h>
#include <graphics/context/AERenderContext.h>
#include <graphics/context/AERenderContextContainer.h>
#include <graphics/AEBaseVideoDevice.h>

#include <graphics/scene/collections/AEMeshBufferCollection.h>
#include <graphics/scene/collections/AEStaticGeometryInstanceCollection.h>

#include <graphics/AERenderNode.h>
#include <graphics/renderer/AERenderer.h>
#include <graphics/renderer/AEBasicRenderNode.h>
#include <graphics/renderer/AEBasicRenderLoop.h>
#include <graphics/renderer/AERenderLoopHelper.h>

#include <visibility/AEVisibilityZone.h>
#include <graphics/scene/AESceneManagerI.h>
#include <graphics/scene/AEDefaultSceneManager.h>

#define AE_NO_ERROR					0
#define AE_CANNOTINITDEVICE			1
#define AE_DEVICENOTSUPPORTED		2

typedef struct _tagAEngineInitParams_
{
	int param1;
	int param2;
}AE_INITPARAMS, *LPAE_INITPARAMS;

AE_DLLIMPEXP void AEngineSDKInit( LPAE_INITPARAMS lpParams = NULL );
//IAEApplication *CreateAEngineApplication( AEWINDOWHANDLE wndAttachToWindow = NULL );
//IAEContext *CreateAEngineContext( IAEApplication *lpApplication, AEWINDOWHANDLE wndAttachToWindow = NULL);

class AE_DLLIMPEXP AEngine
{
// Members
private:
	static AEVideoConfig *m_lpVideoConfig;

protected:
	static IAEVideoDevice *m_lpDevice;
	static AETextureManager *m_lpTextureManager;
	static AEVertexBufferManager *m_lpVertexBufferManager;

	static AERenderContext *m_lpCurrentRenderContext;
	static AERenderer *m_lpRenderer;
	static AERenderNode *m_lpRenderNode;
	static AESceneManagerIPtr m_spSceneManager;

public:
	static AEEngineConfig EngineConfig;
	static AERenderLoopHelper RenderLoopHelper;

	//static AEMemoryConfig *m_lpMemoryConfig;
	//static AEMemoryManager *m_lpMemManager;
// Methods
private:
	static void _fillVideoConfig( void );
	static void _initMemoryManager( void );
	static AEUINT32 _initPlatform( void );
public:
	static AERESULT Init( AEEngineConfig *lpConfig = NULL );
	static AE_FORCEINLINE bool IsInitialized( void );

	static void SetApplication( AEApplication *lpApplication );
	static AE_FORCEINLINE AEApplication *GetApplication( void );
	static void Shutdown( void );

	static void InitWorld( void );
	static void DeInitWorld( void );
	static const char *GetVersion( void );
	static AEUINT32 Run( void );
	static AEVideoConfig *GetDefaultVideoConfig( void );
	static AEEngineConfig *GetEngineConfig( void );
	//static AEMemoryConfig *GetMemConfig( void );

	static AEMemoryManager *GetMemManager( void );
	static AETextureManager *GetTextureManager( void );
	static AEVertexBufferManager *GetVertexBufferManager( void );
	static AERenderContext *GetMainRenderContext( void );
	static AERenderer *GetRenderer( void );

	/// \brief
	///   Sets the global scene manager instance
	/// 
	/// The application holds a reference to the current global scene manager instance, so no custom
	/// cleanup is necessary.
	/// 
	/// \param pSceneManager
	///   Pointer to the new scene manager. The engine increases its reference counter (smart
	///   pointer).
	/// 
	/// \sa IVisSceneManager_cl
	/// \sa VisionSceneManager_cl
	static void SetSceneManager( AESceneManagerI *lpSceneManager );

	/// \brief
	///   Returns the global scene manager instance
	/// 
	/// If no scene manager has been set at this point, the engine creates an instance of class
	/// VisionSceneManager_cl.
	/// 
	/// Thus it is always guaranteed that there is a valid scene manager when requested.
	/// 
	/// \return
	///   the current scene manager. By default, this is an instance of class VisionSceneManager_cl.
	static AESceneManagerI *GetSceneManager( void );
};

AE_DLLIMPEXP inline AEMemoryManager *InitMemorySystem( AEMemoryAllocator *lpMemAllocator, const AEMemoryConfig::AEMemoryConfigInfo &mcInfo );

class AE_DLLIMPEXP AEEngine : public AESystemAccessI
{
// Members
public:
    enum AESysComponents
    {
        System, Scene, Object, Task
    };

protected:
    struct AEPropertyIssue
    {
		AESysComponents	eSystemComponent;
		AEUINT32		uiSystemType;
		AEHANDLE		hItem;
		AEProperty		*lpProperty;
    };

    typedef AETArray<AEPropertyIssue>	AEPropertyIssues;

	//SpinWait						m_PropertyIssuesSpinWait;

	//AEScheduler						*m_lpScheduler;
	AEChangeControlMgr				*m_lpScenesCCM;
	AEChangeControlMgr				*m_lpEntitiesCCM;
	//UScene							*m_lpScene;

	AEBOOL32						m_bExecuteLoop;

	#ifdef __ALLOW_DEBUG_WINDOW__
		AEHANDLE					m_hDebugWindow;
	#endif

	AETextureManager				*m_lpTextureManager;

// Methods
protected:
	// Implementazione metodi di AESystemAccessI
    virtual AEEngineSystem *GetSystem( const char *lpszSystemName );
    virtual AEEngineSystem *GetSystem( AEUINT32 uiSysType );
    virtual AESystemSceneI *GetScene( const char *lpszSceneName );
    virtual AESystemSceneI *GetScene( AEUINT32 uiSysType );
    virtual AESystemObjectI *GetSystemEntity( const char *lpszSystemName, const char *lpszEntityName );
    virtual AESystemObjectI *GetSystemEntity( AEUINT32 uiSysType, const char *lpszEntityName );
    virtual AEProperty *GetSystemProperty( AEEngineSystem *lpSystem, const char *lpPropertyName );
    virtual void SetSystemProperty( AEEngineSystem *lpSystem, AEProperty *lpProperty );
    virtual AEProperty *GetSceneProperty( AESystemSceneI *lpScene, const char *lpPropertyName );
    virtual void SetSceneProperty( AESystemSceneI *lpScene, AEProperty *lpProperty );
    virtual AEProperty *GetEntityProperty( AESystemObjectI *lpEntity, const char *lpPropertyName );
    virtual void SetEntityProperty( AESystemObjectI *lpEntity, AEProperty *lpProperty );

    /// <summary>
    ///   Issues all the pending property changes.  This only occurs after the scheduler has
    ///    executed all the waiting items.
    /// </summary>
    /// <param name="SystemTypes">The system types of the system that can accept property
    ///  changes.</param>
    //void IssuePendingSystemPropertyChanges( System::Types::BitMask SystemTypes=System::Types::All );

public:
	AEEngine( void );
	~AEEngine( void );

	void Shutdown( void );
	AEUINT32 Execute( void );
	AEUINT32 Initialize( void );

};


#endif // _AENGINE_H_
